feat(booking-requests): add optional booking-requests module - #348
Conversation
Introduce @telivityhaip/booking-requests as a deploy-time optional module (HAIP_BOOKING_REQUESTS=true) with separate migrations, Stripe handler delegation, and dashboard/booking widget feature flags. Core instant booking paths stay unchanged when the flag is off. Includes booking request API/controllers, schema split (0022-0032), email transport hardening, webhook logicalEventId dedup, and CI release-gate job. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Remove email transport, webhook dedup, shared utils, test-count sync, and core webhook migration changes that land in separate focused PRs. Document booking-requests in README packages section and optional enablement steps. Depends on #349, #350, #351, #352, and #353. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Re-include prerequisite core changes so typecheck and docker seed pass. Add booking-requests to CI/Docker builds. Sync README to 2120 tests / 252 files. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
push-schema now creates adjusts_charge_id and source_key so seed and docker init succeed. Webhook logicalEventId spec uses reservation.created from the core WEBHOOK_EVENTS catalog. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Static imports pulled @telivityhaip/booking-requests into the default demo image and crashed startup with missing @nestjs/common. Gate the optional package behind HAIP_BOOKING_REQUESTS and read the flag from core seams. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
4da34ca to
ee16f70
Compare
Avoid loading @telivityhaip/booking-requests at startup when HAIP_BOOKING_REQUESTS is off (docker demo). Preload before Nest bootstrap when the flag is enabled; read the flag from core payment seams in DatabaseModule. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
1461b8f to
5b6a37e
Compare
Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
|
Thanks for doing the separation. I reviewed the current head I do think #348 needs another architecture/packaging pass before it is mergeable:
Additional hardening:
I am happy to review the updated package again. The feature work is strong; the blockers are about making the isolation and deployment behavior match the agreed architecture. |
Resolve guest-comms email stack conflicts using main (#349). Regenerate README test counts after merge. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Resolve conflicts with #349–#353: take main for confirmation-number, connect events, and connect-booking token re-export; merge Stripe financial-state so core one-arg classifyHaipMetadata coexists with booking-request correlation helpers and webhook delegation. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
- Ship runnable migrator + SQL in dist; production db:migrate via node - Wire VITE_HAIP_BOOKING_REQUESTS through Docker/compose/release - Reject bookingMode=request when HAIP_BOOKING_REQUESTS is off - Ledger + checksum for package migrations (auto-commit for PG enums) - Drop unused stripeHandlerToken from root module options - Fix EmailResult outcomeUnknown after #349 status contract - Point regression/e2e installs at run-migrations.js (post-#350) - Harden push-schema CLI path resolution; sync README (2175/259) Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
|
Thanks @agustinjch — working through the packaging/safety pass. Landed on
Still open (as you called out): moving the full vertical slice behind Appreciate the review. |
#350 moved webhook logical_event_id to migration 0022. Remove the column and unique index from push-schema so the pre-0022 upgrade regression passes again. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Matches CI after push-schema logical_event_id cleanup (all packages green). Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
…y specs - Add a flag-OFF default-install regression spec: only core migrations run, HAIP_BOOKING_REQUESTS is unset, AppModule boots without the booking-requests module/tables, request mode is rejected, and instant booking + deposit capture + partial/full refund still work. Runs automatically under `pnpm test` (apps/api's normal *.spec.ts glob), so it is wired into CI without any workflow changes. - Extract the ephemeral-database subprocess helpers shared by that spec and the existing default-flow regression spec into regression-database-utils.ts (createdb/dropdb, sanitized child-process errors) instead of duplicating them. - Port PR #347's booking-request-schema.spec.ts and booking-request-migration-safety.spec.ts into the package, scoped to the tables/migrations this package now owns (the duplicate push-schema DDL those specs cross-checked no longer exists — it moved into this package's migrations). - Port PR #347's booking-request-remediation.postgres.spec.ts, replaying migration 0032's SQL directly (instead of through push-schema) since the ledger-based migrator can't be re-run against a manually-reverted schema. Kept opt-in via BOOKING_REQUEST_REMEDIATION_LIVE_PG like the original. - Document remaining scope (vertical-slice move, push-schema de-pollution) in the package README instead of attempting it in this pass. - Sync README/test-stats test counts (2211 tests, 263 files). Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
|
Follow-up on
Still open, documented in |
…ethod_collection/form_questions Adds BOOKING_REQUEST_CONFIG_FIELDS_PORT + DrizzleBookingRequestConfigFieldsAdapter so the package owns reading/writing booking_engine_config's request-mode-only columns via its own Drizzle table fragment, instead of core declaring them. Wired into BookingRequestModule.forRoot() (global) so it's injectable into core's BookingEngineConfigService without that module importing this package. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Removes booking_mode/payment_method_collection/form_questions ALTERs on booking_engine_config, audit_logs.booking_request_id (+ its timeline index), and the request-shape unique indexes/checks on payments (payments_property_request_*_unique, booking_request_parent_positive_check, booking_request_child_shape_check) from core's push-schema.ts and Drizzle schema. These are now declared and migrated exclusively by packages/booking-requests. payments.booking_request_id/idempotency_key, reservations.accepted_pricing_snapshot, and charges adjusts_charge_id/source_key stay in core as documented in push-schema-kept-fields.spec.ts. Also adds the DRIZZLE injection token to @telivityhaip/database so packages outside apps/api (booking-requests) can inject the shared Drizzle client without importing apps/api. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Own controllers/services/DTOs behind package ports; strip request-only audit DDL and payment indexes from core schema; keep thin config/payment hooks. - Nest controllers, DTOs, services, Stripe handler, and pricing/money/ state/db/ledger/reconciler/template helpers now live in packages/booking-requests/src (http/ + domain/), with their unit specs. BookingRequestModule.forRoot(...) is a real DynamicModule owning those controllers/providers directly, not a facade over apps/api classes. - apps/api/src/modules/booking-request/ keeps only the e2e, authorization, default-flow-regression, flag-off-instant-booking.regression, and transaction-seams specs plus regression-database-utils.ts. - apps/api/src/booking-requests.bootstrap.ts wires every package-local port (folio, webhook, email, reservation, rate-plan, guest, ancillary, availability, booking-engine, booking-engine-config, plus guard-bridge ports) to the concrete core singleton via `useExisting`. - Guard bridge classes (BookingKeyGuardBridge, BookingEngineScopeGuardBridge, BookingThrottleGuardBridge) resolve the "guards landmine": @UseGuards(...) is populated from decorator metadata, a separate path from `providers`, so a bare useExisting binding on an abstract port class is silently dropped — the bridges are real injectable classes referenced in @UseGuards(...). - DRIZZLE token declaration moved to @telivityhaip/database; apps/api's DatabaseModule still @Global-provides it and merges in the package's optional schema only when HAIP_BOOKING_REQUESTS is on. - Relocated pure/shared pieces to packages/shared: SAVED_PAYMENT_METHOD_GATEWAY / PAYMENT_GATEWAY / BOOKING_REQUEST_STRIPE_HANDLER interfaces, IsMoneyString, canonical calendar date validators, stayDates, AuditActor helpers, RequirePermissions/Public decorators, stripe-financial-state helpers, and the pure payment-ledger math (remainingCapturedAmount/sumRefundChildren) — bookingRequestPaymentSumWhere stays in core payment-ledger. - Schema de-pollution: removed audit_logs.booking_request_id (+ its timeline index) and the request-shape payments unique indexes/checks from core push-schema/drizzle; kept booking_engine_config.booking_mode / payment_method_collection / form_questions, payments.booking_request_id / idempotency_key, reservations.accepted_pricing_snapshot, and charges adjusts_charge_id/source_key as thin config/payment hooks core still reads directly. packages/database/src/push-schema-kept-fields.spec.ts guards the contract; packages/booking-requests declares its own local audit table extension for the timeline index it still owns. - EventEmitterModule.forRoot() re-enabled `wildcard: true` — required for the webhook fan-out (@onevent('**')) to receive booking-request events. - README's "Package boundary" section replaces the old "Remaining work" deferrals list with an accurate description of the current split. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
Shared now requires @nestjs/common at runtime after the booking-requests boundary move; copy packages/shared/node_modules into the API image so demo smoke can boot. Sync published test counts to 2222/266. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
|
@agustinjch All six architecture blockers from your review are done on head
Also landed: migration ledger + checksum, unused Package boundary now: controllers/DTOs/domain services/Stripe handler/unit specs live under Core schema: request-only Ready for your re-review / merge whenever you are. Thanks again for the packaging pass — it made the isolation real. |
When HAIP_BOOKING_REQUESTS=true, AppModule evaluates bookingRequestsModules() at import time; dynamic-import AppModule after preload so flag-on dev/prod boot does not crash before Nest starts. Co-authored-by: telivity-otaip <telivity-otaip@users.noreply.github.com>
|
Follow-up on |
Summary
Adds
@telivityhaip/booking-requestsas an optional workspace package for request-first direct booking. Core instant booking remains the default when the feature flag is off.Architecture (Agustin review addressed)
packages/booking-requests.BookingRequestModule.forRoot(...)is a realDynamicModulewith package-local DI ports;apps/apionly wires ports viabooking-requests.bootstrap.ts(useExisting) whenHAIP_BOOKING_REQUESTS=true.dist/database/migrate.js+ SQL assets; Docker ships the package artifact.VITE_HAIP_BOOKING_REQUESTSwired through Dockerfile / compose / release build-args.bookingMode=requestrejected when the module flag is off.push-schema/drizzle; thin hooks kept (payments.booking_request_id, idempotency, accepted pricing snapshot, charge provenance, booking_mode config columns for the fail-safe). Contract covered bypush-schema-kept-fields.spec.ts.Enablement
pnpm db:migratepnpm db:migrate:booking-requestsHAIP_BOOKING_REQUESTS=trueinapps/api/.envVITE_HAIP_BOOKING_REQUESTS=truefor dashboard/booking UI (Docker build-arg)bookingMode=requestin booking engine adminSee
packages/booking-requests/README.md.How to test
Contributor credit
@agustinjch